//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGITTARIUS__SIMPLE_UNICODE_STRING__H_
#define __SAGITTARIUS__SIMPLE_UNICODE_STRING__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.hpp"

#include "sagittarius/unicode/SimpleUnicodeChar.hpp"
#include "sagittarius/patterns/Array.hpp"
#include <sstream>

namespace Sagittarius
{
    
    class SimpleUnicodeString : public Array<SimpleUnicodeChar>
    {
        public:
            typedef SimpleUnicodeChar CharType;
            typedef Array<CharType> Super;
            
            //empty constructor
            SimpleUnicodeString()
            {
            }
            
            //copy constructor
            SimpleUnicodeString(const SimpleUnicodeString& other)
                : Super(other)
                {}
            
            //from C-style string
            SimpleUnicodeString(const char* str)
            {
                From_UTF_8_String(str, get_end_of_buffer(str));
            }
            
            //from std::string string
            explicit SimpleUnicodeString(const std::string& str)
            {
                From_UTF_8_String(str.c_str(), str.c_str()+str.size());
            }
            
            //construct from c-style UTF-8 string
            void From_UTF_8_String(const char* c_str, const char* end_of_buffer)
            {
                clear();
                const char* p(c_str);
                int i=0;
                
                while(*p != '\0' && p < end_of_buffer)
                {
                    push_back(0);
                    try {
                        p = SimpleUChar_From_UTF_8_String(p, end_of_buffer, back());
                        ++i;
                    } catch(Exception e) {
                        std::stringstream s;
                        s << "Error converting character " << i+1 << ", byte " << p-c_str << ": " << e.getDescription();
                        SAGITTARIUS_THROW(SanityCheckException, s.rdbuf()->str(), "SimpleUnicodeString::From_UTF_8_String");
                    }
                }
            }
            
            //construct from stream (usu. file)
            void FromStream(std::istream& is);
            
            //get the total number of bytes in the buffer
            int n_bytes() const
            {
                int result=0;
                for(const_iterator iter(begin()); iter!=end(); ++iter)
                {
                    result += SimpleUChar_nBytes(*iter);
                }
            }
            
            //convert to c-style string
            char* ToC_String()
            {
                _c_str.reset(new char[n_bytes()]);
                char* cursor(_c_str.get());
                //end of buffer
                char* eob(_c_str.get()+n_bytes());
                
                for(const_iterator iter(begin()); iter!=end(); ++iter)
                {
                    cursor = SimpleUChar_toCStr(*iter, cursor, eob);
                    #if SAGITTARIUS_DEBUG_LEVEL >= 1
                        SAGITTARIUS_ASSERT(cursor < eob);
                    #endif
                }
                
                return _c_str.get();
            }
            
            //convert to c-style string
            std::string ToStdString() const
            {
                std::string result;
                if(size() < 1)
                    return result;
                
                for(const_iterator iter(begin()); iter!=end(); ++iter)
                {
                    result += SimpleUChar_toStdStr(*iter);
                }
                
                return result;
            }
            
            //convert to codepoint string
            std::string ToCodepointString() const
            {
                std::string result;
                
                for(const_iterator iter(begin()); iter!=end(); ++iter)
                {
                    result += SimpleUChar_ToCodepointString(*iter);
                }
                
                return result;
            }
            
            //append
            void append(const CharType& chr)
            {
                push_back(chr);
            }
            
            //comparison
            //already defined by Array?
            /*bool operator==(const SimpleUnicodeString& other) const
            {
                //std::cout << "SimpleUnicodeString::operator== started, _buffer == other._buffer = " << (bool)(_buffer == other._buffer) << "\n";
                return _buffer == other._buffer;
            }*/
            
            bool operator!=(const SimpleUnicodeString& other) const
            {
                return !this->operator==(other);
            }
            
            //addition
            const SimpleUnicodeString operator+ (const SimpleUnicodeString& other) const
            {
                SimpleUnicodeString copy(*this);
                for(const_iterator iter(other.begin()); iter!=other.end(); ++iter)
                    copy.push_back(*iter);
                return copy;
            }
            const SimpleUnicodeString operator+ (const char* other) const
            {
                SimpleUnicodeString other_str(other);
                return this->operator+ (other_str);
            }
            
            //from std::string
            /*SimpleUnicodeString& operator=(const std::string& str)
            {
                for(std::string::const_iterator iter(str.begin()); iter!=str.end(); ++iter)
                {
                    CharType uni_char;
                    uni_char.From_UTF_8_String(&(*iter), &(*str.end())); //NOTE: this requires std::string buffer contiguity
                    _buffer.push_back(uni_char);
                }
                return *this;
            }*/
            
            SimpleUnicodeString& operator=(const SimpleUnicodeString& other)
            {
                Super::operator=(other);
                return *this;
            }
            
        protected:
            const char* get_end_of_buffer(const char* str)
            {
                //finds the null character
                const char* ch=str;
                while(*ch != '\0')
                    ++ch;
                return ch;
            }
            
            boost::scoped_array<char> _c_str;
    };
    
    //stream I/O
    std::ostream& operator<<(std::ostream& os, const SimpleUnicodeString& str);
    
} //namespace Sagittarius

#endif
